﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Collections;
using System.IO;
using System.Drawing;
using ICSharpCode.SharpZipLib.Zip.Compression;

namespace RungSoft.RungEBookMaker.Providers.DocFormater.Umd
{
    class UmdReader
    {   
        // Fields
        private uint _AdditionalCheckNumber;
        private BookBM _Book = null;
        private int[] _ChaptersOff = null;
        private string _Publish_Day = string.Empty;
        private string _Publish_Month = string.Empty;
        private string _Publish_Year = string.Empty;
        private int _TotalContentLen = 0;
        private List<Image> _TotalImageList = new List<Image>();
        private ArrayList _ZippedContentList = new ArrayList();

        // Methods
        private ChapterBM GetChapter(int index)
        {
            if (index != this._Book.Chapters.Count)
            {
                throw new Exception("堆栈溢出！");
            }
            this._Book.Chapters.Add(new ChapterBM());
            return this._Book.Chapters[index];
        }

        private void ParseChapterImages()
        {
            int count = 0;
            for (int i = 0; i < this._Book.Chapters.Count; i++)
            {
                if (i < (this._Book.Chapters.Count - 1))
                {
                    count = this._ChaptersOff[i + 1];
                }
                else
                {
                    count = this._TotalImageList.Count;
                }
                int num1 = this._ChaptersOff[i];
                for (int j = this._ChaptersOff[i]; j < count; j++)
                {
                    this._Book.Chapters[i].AppendImage((Image)this._TotalImageList[j]);
                }
            }
            if (count < this._TotalImageList.Count)
            {
                ChapterBM chapter = new ChapterBM("未知", string.Empty);
                for (int k = count; k < this._TotalImageList.Count; k++)
                {
                    chapter.AppendImage((Image)this._TotalImageList[k]);
                }
                this._Book.AppendChapter(chapter);
            }
            this._TotalImageList.Clear();
        }

        private void ParseChapterTxtContents()
        {
            int destinationIndex = 0;
            byte[] destinationArray = new byte[this._TotalContentLen];
            byte[] buf = new byte[0x8000];
            foreach (byte[] buffer3 in this._ZippedContentList)
            {
                Inflater inflater = new Inflater();
                inflater.SetInput(buffer3);
                inflater.Inflate(buf);
                if (destinationIndex < destinationArray.Length)
                {
                    Array.Copy(buf, 0, destinationArray, destinationIndex, Math.Min(destinationArray.Length - destinationIndex, inflater.TotalOut));
                    destinationIndex += inflater.TotalOut;
                }
            }
            for (int i = 0; i < this._ChaptersOff.Length; i++)
            {
                int index = this._ChaptersOff[i];
                int count = 0;
                if (i < (this._ChaptersOff.Length - 1))
                {
                    count = this._ChaptersOff[i + 1] - index;
                }
                else
                {
                    count = destinationArray.Length - index;
                }
                this._Book.Chapters[i].Content = this._Book.Encoding.GetString(destinationArray, index, count).Replace("\u2029", "\r\n");
            }
            this._ZippedContentList.Clear();
        }

        private void Read(BinaryReader reader)
        {
            if (reader.ReadUInt32() != StaticFunctions.CMD_DATA_SECTION_HEADER)
            {
                throw new ApplicationException("UMD文件头验证错误。");
            }
            short num2 = -1;
            char ch = (char)reader.PeekChar();// 预读下一个字符

            while (ch == '#')
            {
                #region UMD文件格式解读
                /*
                 * =========UMD文件额外数据区===========
                 * 0x23 0x01 0x00 0x08 0x01 （必须的）
                 *      0x01/0x02 （0x01代表文本格式的UMD文件,0x02代表动漫格式的UMD文件）
                 *      0x## 0x## （两个随机字符）
                 * 0x23 0x02 0x00 （书名）
                 *      0x00 （必须的）
                 *      0x## （书名 的长度*2 + 5）
                 *      0x##...（书名 的内容）
                 * 0x23 0x03 0x00 （作者）
                 *      0x00 （必须的）
                 *      0x## （作者 的长度*2 + 5）
                 *      0x##...（作者 的内容）
                 * 0x23 0x04 0x00 （year ）
                 * 0x23 0x05 0x00 （mouth ）
                 * 0x23 0x06 0x00 （day ）
                 * 0x23 0x07 0x00 （Gender ）
                 * 0x23 0x08 0x00 （Publisher ）
                 * 0x23 0x09 0x00 （Vendor ）
                 * 
                 * =========UMD文件目录正文区===========
                 * 0x23 0x0B 0x00 （内容长度 =11）
                 *      0x00 0x09 （必须的）
                 *      0x## 0x## 0x## 0x##（内容长度）
                 * 0x23 0x83 0x00 （章节偏移量）
                 *      0x01 0x09
                 *      0x## 0x## 0x## 0x##（随机数A1,目前看来是起同步作用的）
                 *      0x24 （字符'$'）
                 *      0x## 0x## 0x## 0x##（随机数B1,与A1相同，目前看来是起同步作用的）
                 *      0x## 0x## 0x## 0x##（偏移量的长度*4 + 9）？？章节数目？？
                 *     [0x## 0x## 0x## 0x##]... （每个节代表一个章节的偏移量，节的个数与章节数相同）
                 * 0x23 0x84 0x00 （章节标题）
                 *      0x01 0x09
                 *      0x## 0x## 0x## 0x##（随机数A2,目前看来是起同步作用的）
                 *      0x24 （字符'$'）
                 *      0x## 0x## 0x## 0x##（随机数B2,与A2相同，目前看来是起同步作用的）
                 *      0x23 0x00 0x00 （字符'#'）
                 *      循环
                 *           0x## 0x## （标题的长度*2）
                 *           0x##...（标题的内容）
                 *      循环结束
                 *      0x24 （字符'$'）
                 *      0x## 0x## 0x## 0x##（随机数）
                 *      0x## 0x## 0x## 0x##（数据流的长度 + 9）
                 *      0x##...（数据流的内容）
                 * 0x23 0XF1 0X00 0X00 0X15 （）
                 *      0x00...（16个0x00）
                 * 0x23 0X0A 0X00 0X00 0X09 （）
                 *      0x## 0x## 0x## 0x##（随机数）
                 * 0x23 0X81 0X00 0X01 0X09 （）
                 *      0x## 0x## 0x## 0x##（随机数）
                 *      0x24 （字符'$'）
                 *      0x## 0x## 0x## 0x##（随机数）
                 *      0x## 0x## 0x## 0x##（页面数*4 + 9）
                 *      0x##...（页面数*4个字节）
                 * 0x23 0X82 0X00 （封面图）
                 *      0X01 0X0A 0X01 （必须的）
                 *      0x## 0x## 0x## 0x##（随机数）
                 *      0x24 （字符'$'）
                 *      0x## 0x## 0x## 0x##（随机数）
                 *      0x## 0x## 0x## 0x##（封面长度 + 9）
                 *      0x##...（封面长度个字节）
                 * 0x23 0X0C 0X00 0X01 0X09 （文件长度）
                 *      0x## 0x## 0x## 0x##（整个文件长度）
                 *      
                 * =============结束===============
                 */

                #endregion

                reader.ReadChar();// 读掉这个'#'
                short segType = reader.ReadInt16();
                byte segFlag = reader.ReadByte();
                byte length = (byte)(reader.ReadByte() - 5);
                this.ReadSection(segType, segFlag, length, reader);

                switch (segType)
                {
                    case 0xf1:
                    case 10:
                        segType = num2;
                        break;
                }
                num2 = segType;

                #region 若下一个字符是'$'，则读取
                ch = (char)reader.PeekChar();
                while (ch == '$')
                {
                    reader.ReadChar();
                    uint additionalCheckNumber = reader.ReadUInt32();
                    uint length1 = reader.ReadUInt32() - 9;
                    this.ReadAdditionalSection(segType, additionalCheckNumber, length1, reader);

                    ch = (char)reader.PeekChar();
                } 
                #endregion
                Console.WriteLine("BEGIN");
                Console.WriteLine((int)segType);
                Console.WriteLine(ch);
                Console.WriteLine("END");
            }
        }

        public BookBM Read(string filepath)
        {
            this._Book = new BookBM();

            if (!File.Exists(filepath)) throw new Exception("找不到" + filepath);

            using (FileStream input = new FileStream(filepath, FileMode.Open, FileAccess.Read))
            {
                if (!input.CanRead) throw new Exception("文件正在被使用，无法读取！");

                using (BinaryReader reader = new BinaryReader(input))
                {
                    try
                    {
                        this.Read(reader);
                    }
                    catch (Exception ex)
                    {
                        this._Book = null;
                        throw ex;
                    }
                }
            }

            if (this._Book.Formate[1] == StaticFunctions.BookType.BOOK_TYPE_TEXT[1])// 文本型UMD
                this.ParseChapterTxtContents();
            else if (this._Book.Formate[1] == StaticFunctions.BookType.BOOK_TYPE_CARTTON[1])// 漫画型UMD
                this.ParseChapterImages();

            this._Book.FilePath = filepath;
            return this._Book;
        }

        /// <summary>
        /// 读取额外数据块（即'$'）。
        /// </summary>
        /// <param name="segType">数据块类别</param>
        /// <param name="additionalCheckNumber">校验字符（0x00）</param>
        /// <param name="length">数据块长度</param>
        /// <param name="reader">数据块</param>
        protected virtual void ReadAdditionalSection(short segType, uint additionalCheckNumber, uint length, BinaryReader reader)
        {
            switch (segType)
            {
                case 0x0E:
                case 0x0F:
                    {
                        Image image = Image.FromStream(new MemoryStream(reader.ReadBytes((int)length)));
                        this._TotalImageList.Add(image);
                        return;
                    }
                case StaticFunctions.CMD_SEC_PAGE_COUNT:// 页面数
                    reader.ReadBytes((int)length);
                    return;

                case StaticFunctions.CMD_SEC_COVER_IMAGE:// 封面图片
                    this._Book.Cover = Image.FromStream(new MemoryStream(reader.ReadBytes((int)length)));
                    return;

                case StaticFunctions.CMD_SEC_CHAPTER_OFFSET:// 章节偏移量
                    this._ChaptersOff = null;
                    this._ChaptersOff = new int[length / 4];
                    for (int i = 0; i < this._ChaptersOff.Length; i++)
                    {
                        this._ChaptersOff[i] = reader.ReadInt32();
                    }
                    return;

                case StaticFunctions.CMD_SEC_CHAPTER_TITLE:// 章节标题
                    if (this._AdditionalCheckNumber == additionalCheckNumber)
                    {
                        int index = 0;
                        byte[] bytes = reader.ReadBytes((int)length);
                        while (index < bytes.Length)
                        {
                            byte count = bytes[index];
                            index++;
                            this._Book.Chapters.Add(new ChapterBM(this._Book.Encoding.GetString(bytes, index, count), string.Empty));
                            index += count;
                        }
                        return;
                    }

                    this._ZippedContentList.Add(reader.ReadBytes((int)length));
                    return;
            }

            string exMsg = string.Format("【未知内容】\r\nSeg Type = {0}\r\nSeg Len = {1}content = {2}", segType, length, reader.ReadBytes((int)length));
            throw(new Exception(exMsg));
        }

        /// <summary>
        /// 读取数据块。
        /// </summary>
        /// <param name="segType">数据块类别</param>
        /// <param name="segFlag"></param>
        /// <param name="length">数据块长度</param>
        /// <param name="reader">数据块</param>
        protected void ReadSection(short segType, byte segFlag, byte length, BinaryReader reader)
        {
            switch (segType)
            {
                case StaticFunctions.CMD_SEC_FILE_HEAD:
                    this._Book.Formate[0] = reader.ReadByte();
                    this._Book.Formate[1] = this._Book.Formate[0];
                    reader.ReadInt16();
                    return;

                case StaticFunctions.CMD_SEC_TITLE:
                    this._Book.Title = this._Book.Encoding.GetString(reader.ReadBytes(length));
                    return;

                case StaticFunctions.CMD_SEC_AUTHOR:
                    this._Book.Author = this._Book.Encoding.GetString(reader.ReadBytes(length));
                    return;

                case StaticFunctions.CMD_SEC_YEAR:
                    this._Publish_Year = this._Book.Encoding.GetString(reader.ReadBytes(length));
                    return;

                case StaticFunctions.CMD_SEC_MONTH:
                    this._Publish_Month = this._Book.Encoding.GetString(reader.ReadBytes(length));
                    return;

                case StaticFunctions.CMD_SEC_DAY:
                    this._Publish_Day = this._Book.Encoding.GetString(reader.ReadBytes(length));
                    return;

                case StaticFunctions.CMD_SEC_GENDER:
                    this._Book.Kind = this._Book.Encoding.GetString(reader.ReadBytes(length));
                    return;

                case StaticFunctions.CMD_SEC_PUBLISHER:
                    this._Book.Publisher = this._Book.Encoding.GetString(reader.ReadBytes(length));
                    return;

                case StaticFunctions.CMD_SEC_VENDOR:
                    this._Book.Vendor = this._Book.Encoding.GetString(reader.ReadBytes(length));
                    return;

                case 10:
                    reader.ReadInt32();
                    return;

                case StaticFunctions.CMD_SEC_CONTENT_LENGTH:
                    this._TotalContentLen = reader.ReadInt32();
                    return;

                case 12:
                    reader.ReadUInt32();
                    return;

                case 13:
                    Console.WriteLine("Seq type = " + 13);
                    Console.WriteLine(reader.ReadUInt32());
                    return;

                case 14:
                    reader.ReadByte();
                    return;

                case 15:
                    reader.ReadBytes(length);
                    this._Book.Formate[0] = 3;
                    return;

                case StaticFunctions.CMD_SEC_PAGE_COUNT:
                case StaticFunctions.CMD_SEC_CHAPTER_OFFSET:
                case StaticFunctions.CMD_SEC_CHAPTER_TITLE:
                    this._AdditionalCheckNumber = reader.ReadUInt32();
                    return;

                case StaticFunctions.CMD_SEC_COVER_IMAGE:
                    reader.ReadByte();
                    this._AdditionalCheckNumber = reader.ReadUInt32();
                    return;
            }
            byte[] buffer = reader.ReadBytes(length);

            Console.WriteLine("未知编码");
            Console.WriteLine("Seg Type = " + segType);
            Console.WriteLine("Seg Flag = " + segFlag);
            Console.WriteLine("Seg Len = " + length);
            Console.WriteLine("Seg content = " + buffer.ToString());
        }

    }
}
